package com.googlecode.connectlet.crypto.cipher.mode.provider;

import java.security.AlgorithmParameters;
import java.security.InvalidAlgorithmParameterException;
import java.security.Key;
import java.security.SecureRandom;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.InvalidParameterSpecException;

import javax.crypto.spec.IvParameterSpec;

import com.googlecode.connectlet.crypto.EasyProvider;
import com.googlecode.connectlet.crypto.cipher.CipherFactory;
import com.googlecode.connectlet.crypto.cipher.mode.CbcCipher;
import com.googlecode.connectlet.crypto.cipher.mode.CbcNoPaddingDecipheror;
import com.googlecode.connectlet.crypto.cipher.mode.CbcNoPaddingEncipheror;

public class CbcNoPaddingCipherSpi extends EcbNoPaddingCipherSpi {
	private IvParameterSpec paramSpec;

	public CbcNoPaddingCipherSpi(CipherFactory cipherFactory) {
		super(cipherFactory);
	}

	@Override
	protected CbcNoPaddingEncipheror getEncCipher(CipherFactory factory, byte[] key) {
		return new CbcNoPaddingEncipheror(factory.getEncipheror(key));
	}

	@Override
	protected CbcNoPaddingDecipheror getDecCipher(CipherFactory factory, byte[] key) {
		return new CbcNoPaddingDecipheror(factory.getDecipheror(key));
	}

	@Override
	protected void reset() {
		((CbcCipher) cipher).init(paramSpec.getIV());
	}

	@Override
	protected void engineInit(int opmode, Key key, SecureRandom random) {
		byte[] iv = new byte[cipherFactory.getBlockSize()];
		random.nextBytes(iv);
		paramSpec = new IvParameterSpec(iv);
		init(opmode, key);
		reset();
	}

	@Override
	protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params,
			SecureRandom random) throws InvalidAlgorithmParameterException {
		if (params instanceof IvParameterSpec) {
			paramSpec = (IvParameterSpec) params;
		} else {
			throw new InvalidAlgorithmParameterException("IvParameterSpec required");
		}
		init(opmode, key);
		reset();
	}

	@Override
	protected void engineInit(int opmode, Key key, AlgorithmParameters params,
			SecureRandom random) throws InvalidAlgorithmParameterException {
		try {
			paramSpec = params.getParameterSpec(IvParameterSpec.class);
		} catch (InvalidParameterSpecException e) {
			throw new InvalidAlgorithmParameterException(e);
		}
		init(opmode, key);
		reset();
	}

	@Override
	protected byte[] engineGetIV() {
		return paramSpec.getIV();
	}

	@Override
	protected AlgorithmParameters engineGetParameters() {
		try {
			AlgorithmParameters result = AlgorithmParameters.
					getInstance("IV", EasyProvider.getInstance());
			result.init(paramSpec);
			return result;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
}